
#include <BWidget>
#include <BPainter>
#include <BMouseEvent>
#include <BGridLayout>
#include "member_BGridLayout.h"
#include "member_BWidget.h"
#include "member_BSpacer.h"
#include "member_BSpring.h"

using namespace BWE;

#define member					(*(member_BGridLayout*)_ptr)
#define member_allocate()		_ptr = new member_BGridLayout(this)
#define member_release()		delete (member_BGridLayout*)_ptr

BGridLayout::BGridLayout(BWidget* host) : BLayout(host)
{
	member_allocate();
}
BGridLayout::BGridLayout(const BString& name, BWidget* host) : BLayout(name, host)
{
	member_allocate();
}
BGridLayout::BGridLayout(Policy widthPolicy, Policy heightPolicy, BWidget* host) : BLayout(host)
{
	member_allocate();
	this->setSizePolicy(BSizePolicy(widthPolicy, heightPolicy));
}
BGridLayout::~BGridLayout()
{
	clear();
	member_release();
}

void BGridLayout::setSpacing(int spacing)
{
	if (member.spacing != spacing)
	{
		member.spacing = spacing;
		BLayout::dirty();
	}
}
int BGridLayout::spacing() const
{
	return member.spacing;
}

void BGridLayout::setHandleSize(const BSize& handleSize)
{
	if (member.handleSize != handleSize)
	{
		member.handleSize = handleSize;
		this->fresh();
	}
}
const BSize& BGridLayout::handleSize() const
{
	return member.handleSize;
}

bool BGridLayout::setRowCount(int rowCount)
{
	if (rowCount < 0 || rowCount > 1000)
		return false;
	if (member.items.row() > rowCount)
	{
		return this->removeRows(rowCount, member.items.row() - rowCount);
	}
	if (member.items.row() < rowCount)
	{
		member.expandTable(rowCount - 1, member.colHeads.size());
		member.dirty = true;
		BLayout::dirty();
	}
	return true;
}
int BGridLayout::rowCount() const
{
	return member.items.row();
}

bool BGridLayout::setColumnCount(int columnCount)
{
	if (columnCount < 0 || columnCount > 1000)
		return false;
	if (member.items.column() > columnCount)
	{
		return removeColumns(columnCount, member.items.column() - columnCount);
	}
	if (member.items.column() < columnCount)
	{
		member.expandTable(member.rowHeads.size(), columnCount - 1);
		member.dirty = true;
		if (!layout_member(this)->dirty)
			BLayout::dirty();
	}
	return true;
}
int BGridLayout::columnCount() const
{
	return member.items.column();
}

bool BGridLayout::setAlign(int row, int column, Align align)
{
	if (!member.items.check(row, column))
		return false;
	LayoutItem& item = member.items[row][column];
	if (item.align != align)
	{
		item.align = align;
		member.dirtyCell(row, column);
		BLayout::dirty();
	}
	return true;
}
Align BGridLayout::align(int row, int column) const
{
	if (!member.items.check(row, column))
		return Align_None;
	LayoutItem& item = member.items[row][column];
	return item.align;
}

bool BGridLayout::setAlign(BObject* object, Align align)
{
	auto it = member.items.find(object);
	if (it.valid())
	{
		LayoutItem& item = *it;
		if (item.align != align)
		{
			item.align = align;
			BLayout::dirty();
		}
		return true;
	}
	return false;
}
Align BGridLayout::align(BObject* object) const
{
	auto it = member.items.find(object);
	if (it.valid())
	{
		LayoutItem& item = *it;
		return item.align;
	}
	return Align_None;
}

bool BGridLayout::setStretch(int row, int column, const BSizeStretch& stretch)
{
	if (!member.items.check(row, column))
		return false;
	LayoutItem& item = member.items[row][column];
	if (item.stretch != stretch)
	{
		item.stretch = stretch;
		BLayout::dirty();
	}
	return true;
}
const BSizeStretch& BGridLayout::stretch(int row, int column) const
{
	return member.items(row, column).stretch;
}

bool BGridLayout::setStretch(BObject* object, const BSizeStretch& stretch)
{
	if (!object)
		return false;
	for (int i = 0; i < member.items.size(); i++)
	{
		LayoutItem& item = member.items.at(i);
		if (item == object)
		{
			if (item.stretch != stretch)
			{
				item.stretch = stretch;
				BLayout::dirty();
				return true;
			}
		}
	}
	return false;
}
const BSizeStretch& BGridLayout::stretch(BObject* object) const
{
	if (object)
	{
		for (int i = 0; i < member.items.size(); i++)
		{
			LayoutItem& item = member.items.at(i);
			if (item == object)
			{
				return item.stretch;
			}
		}
	}
	return member.items.def().stretch;
}

bool BGridLayout::setColumnStretch(int column, float stretch)
{
	if (column < 0 || column > 100)
		return false;
	if (!member.colHeads.check(column))
		this->setColumnCount(column + 1);
	if (member.colHeads[column].fixedStretch != stretch)
	{
		member.colHeads[column].fixedStretch = stretch;
		member.colHeads[column].dirty = true;
		member.dirty = true;
		BLayout::dirty();
	}
	return true;
}
float BGridLayout::columnStretch(int column) const
{
	return member.colHeads(column).fixedStretch;
}

bool BGridLayout::setRowStretch(int row, float stretch)
{
	if (row < 0 || row > 100)
		return false;
	if (!member.rowHeads.check(row))
		this->setRowCount(row + 1);
	if (member.rowHeads[row].fixedStretch != stretch)
	{
		member.rowHeads[row].fixedStretch = stretch;
		member.rowHeads[row].dirty = true;
		member.dirty = true;
		BLayout::dirty();
	}
	return true;
}
float BGridLayout::rowStretch(int row) const
{
	return member.rowHeads(row).fixedStretch;
}

bool BGridLayout::setColumnPolicy(int column, Policy policy)
{
	if (column < 0 || column > 100)
		return false;
	if (!member.colHeads.check(column))
		this->setColumnCount(column + 1);
	if (member.colHeads[column].fixedPolicy != policy)
	{
		member.colHeads[column].fixedPolicy = policy;
		member.colHeads[column].dirty = true;
		member.dirty = true;
		BLayout::dirty();
	}
	return true;
}
Policy BGridLayout::columnPolicy(int column) const
{
	return member.colHeads(column).fixedPolicy;
}

bool BGridLayout::setRowPolicy(int row, Policy policy)
{
	if (row < 0 || row > 100)
		return false;
	if (!member.rowHeads.check(row))
		this->setRowCount(row + 1);
	if (member.rowHeads[row].fixedPolicy != policy)
	{
		member.rowHeads[row].fixedPolicy = policy;
		member.rowHeads[row].dirty = true;
		member.dirty = true;
		BLayout::dirty();
	}
	return true;
}
Policy BGridLayout::rowPolicy(int row) const
{
	return member.rowHeads(row).fixedPolicy;
}

bool BGridLayout::setWidget(int row, int column, BWidget* widget, Align align)
{
	if (this->host() == widget)
		return false;
	if (widget && widget_member(widget)->upperLayout == this)
	{
		auto it = member.items.find(widget);
		if (it.row() != row || it.column() != column)
		{
			LayoutItem& item = member.items(row, column);
			item = widget;
			it->clear();
			member.dirty = true;
			BLayout::dirty();
		}
		return true;
	}
	member.expandTable(row, column);
	LayoutItem& item = member.items[row][column];
	item.clear();
	item.widget = widget;
	item.align = align;
	if (widget)
	{
		if (widget_member(widget)->upperLayout)
			widget_member(widget)->upperLayout->remove(widget);
		widget_member(widget)->upperLayout = this;
		if (layout_member(this)->host)
			layout_member(this)->host->addChild(widget);
	}
	member.dirtyCell(row, column);
	BLayout::dirty();
	return true;
}
bool BGridLayout::setLayout(int row, int column, BLayout* layout, Align align)
{
	if (layout == this)
		return false;
	if (layout && layout_member(layout)->parent == this)
	{
		auto it = member.items.find(layout);
		if (it.row() != row || it.column() != column)
		{
			LayoutItem& item = member.items(row, column);
			item = layout;
			it->clear();
			member.dirty = true;
			BLayout::dirty();
		}
		return true;
	}
	member.expandTable(row, column);
	LayoutItem& item = member.items[row][column];
	item.clear();
	item.layout = layout;
	item.align = align;
	if (layout)
	{
		if (layout_member(layout)->parent)
			layout_member(layout)->parent->remove(layout);
		layout_member(layout)->parent = this;
		layout->setHost(layout_member(this)->host);
	}
	member.dirtyCell(row, column);
	BLayout::dirty();
	return true;
}
bool BGridLayout::setSpacer(int row, int column, BSpacer* spacer, Align align)
{
	if (spacer && spacer_member(spacer)->layout == this)
	{
		auto it = member.items.find(spacer);
		if (it.row() != row || it.column() != column)
		{
			LayoutItem& item = member.items(row, column);
			item = spacer;
			it->clear();
			member.dirty = true;
			BLayout::dirty();
		}
		return true;
	}
	member.expandTable(row, column);
	LayoutItem& item = member.items[row][column];
	item.clear();
	item = spacer;
	item.align = align;
	if (spacer)
	{
		if (spacer_member(spacer)->layout)
			spacer_member(spacer)->layout->remove(spacer);
		spacer_member(spacer)->layout = this;
	}
	member.dirtyCell(row, column);
	BLayout::dirty();
	return true;
}
bool BGridLayout::setSpring(int row, int column, BSpring* spring, const BSizeStretch& stretch)
{
	if (spring && spring_member(spring)->layout == this)
	{
		auto it = member.items.find(spring);
		if (it.row() != row || it.column() != column)
		{
			LayoutItem& item = member.items(row, column);
			item = spring;
			it->clear();
			member.dirty = true;
			BLayout::dirty();
		}
		return true;
	}
	member.expandTable(row, column);
	LayoutItem& item = member.items(row, column);
	item.clear();
	item.spring = spring;
	item.stretch = stretch;
	if (spring)
	{
		if (spring_member(spring)->layout)
			spring_member(spring)->layout->remove(spring);
		spring_member(spring)->layout = this;
	}
	member.dirtyCell(row, column);
	BLayout::dirty();
	return true;
}

BSpacer* BGridLayout::setSpacer(int row, int column, const BSize& size, Align align)
{
	BSpacer* spacer = new BSpacer(size);
	setSpacer(row, column, spacer, align);
	return spacer;
}
BSpring* BGridLayout::setSpring(int row, int column, const BSizeStretch& stretch)
{
	BSpring* spring = new BSpring();
	setSpring(row, column, spring, stretch);
	return spring;
}

bool BGridLayout::remove(int row, int column)
{
	if (!member.items.check(row, column))
		return false;
	LayoutItem& item = member.items(row, column);
	if (item.empty())
		return false;
	if (item.layout)
	{
		item.layout->setHost(0);
		layout_member(item.layout)->parent = 0;
		item.layout = 0;
	}
	if (item.widget)
	{
		widget_member(item.widget)->upperLayout = 0;
		if (this->host())
			this->host()->removeChild(item.widget);
		item.widget = 0;
	}
	if (item.spring)
	{
		item.spring = 0;
	}
	if (item.spacer)
	{
		item.spacer = 0;
	}
	member.dirty = true;
	BLayout::dirty();
	return true;
}
bool BGridLayout::removeRow(int row)
{
	return removeRows(row, 1);
}
bool BGridLayout::removeRows(int row, int count)
{
	if (row >= member.items.row())
		return false;
	int end = row + count;
	if (end > member.items.row())
		end = member.items.row();
	for (int c = 0; c < member.items.column(); c++)
	{
		member.colHeads[c].dirty = true;
		for (int r = row; r < end; r++)
		{
			LayoutItem& item = member.items[r][c];
			if (item.empty())
				continue;
			if (item.layout)
			{
				item.layout->setHost(0);
				layout_member(item.layout)->parent = 0;
				item.layout = 0;
			}
			if (item.widget)
			{
				widget_member(item.widget)->upperLayout = 0;
				if (this->host())
					this->host()->removeChild(item.widget);
				item.widget = 0;
			}
			if (item.spring)
			{
				item.spring = 0;
			}
			if (item.spacer)
			{
				item.spacer = 0;
			}
		}
	}
	member.items.removeRow(row, count);
	member.rowHeads.remove(row, count);
	member.dirty = true;
	BLayout::dirty();
	return true;
}
bool BGridLayout::removeColumn(int column)
{
	return removeColumns(column, 1);
}
bool BGridLayout::removeColumns(int column, int count)
{
	if (column >= member.items.column())
		return false;
	int endColumn = column + count;
	if (endColumn > member.items.column())
		endColumn = member.items.column();
	for (int r = 0; r < member.items.row(); r++)
	{
		member.rowHeads[r].dirty = true;
		for (int c = column; c < endColumn; c++)
		{
			LayoutItem& item = member.items[r][c];
			if (item.empty())
				continue;
			if (item.widget)
			{
				widget_member(item.widget)->upperLayout = 0;
				if (this->host())
					this->host()->removeChild(item.widget);
				item.widget = 0;
			}
			if (item.layout)
			{
				item.layout->setHost(0);
				layout_member(item.layout)->parent = 0;
				item.layout = 0;
			}
			if (item.spring)
			{
				spring_member(item.spring)->layout = 0;
				item.spring = 0;
			}
			if (item.spacer)
			{
				spacer_member(item.spacer)->layout = 0;
				item.spacer = 0;
			}
		}
	}
	member.items.removeColumn(column, count);
	member.colHeads.remove(column, count);
	member.dirty = true;
	BLayout::dirty();
	return true;
}

BWidget* BGridLayout::widget(int row, int column) const
{
	if (member.items.check(row, column))
	{
		LayoutItem& item = member.items[row][column];
		return item.widget;
	}
	return 0;
}
BLayout* BGridLayout::layout(int row, int column) const
{
	if (member.items.check(row, column))
	{
		LayoutItem& item = member.items[row][column];
		return item.layout;
	}
	return 0;
}
BSpacer* BGridLayout::spacer(int row, int column) const
{
	if (member.items.check(row, column))
	{
		LayoutItem& item = member.items[row][column];
		return item.spacer;
	}
	return 0;
}
BSpring* BGridLayout::spring(int row, int column) const
{
	if (member.items.check(row, column))
	{
		LayoutItem& item = member.items[row][column];
		return item.spring;
	}
	return 0;
}

BRect BGridLayout::cellRect(int row, int column)
{
	return member.items(row, column).rect;
}

void BGridLayout::setHost(BWidget* host)
{
	if (this->contain(host))
		return;
	if (this->host() == host)
		return;
	if (BWidget* host = layout_member(this)->host)
	{
		for (auto it = member.items.begin(); it != member.items.end(); it++)
		{
			LayoutItem& item = *it;
			if (item.widget)
				host->removeChild(item.widget);
			if (item.layout)
				item.layout->setHost(0);
		}
	}
	layout_member(this)->host = host;
	if (BWidget* widget = this->host())
	{
		for (auto it = member.items.begin(); it != member.items.end(); it++)
		{
			LayoutItem& item = *it;
			if(item.widget)
				host->addChild(item.widget);
			if (item.layout)
				item.layout->setHost(host);
		}
	}
	BLayout::dirty();
}

int BGridLayout::count() const
{
	return member.items.size();
}
BObject* BGridLayout::object(int pos) const
{
	LayoutItem& item = member.items.at(pos);
	if (item.widget)
		return item.widget;
	if (item.layout)
		return item.layout;
	if (item.spacer)
		return item.spacer;
	if (item.spring)
		return item.spring;
	return 0;
}
BWidget* BGridLayout::widget(int pos) const
{
	LayoutItem& item = member.items.at(pos);
	return item.widget;
}
BLayout* BGridLayout::layout(int pos) const
{
	LayoutItem& item = member.items.at(pos);
	return item.layout;
}
BSpacer* BGridLayout::spacer(int pos) const
{
	LayoutItem& item = member.items.at(pos);
	return item.spacer;
}
BSpring* BGridLayout::spring(int pos) const
{
	LayoutItem& item = member.items.at(pos);
	return item.spring;
}

bool BGridLayout::dirty(const BObject* object) const
{
	for (int r = 0; r < member.items.row(); r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			LayoutItem& item = member.items[r][c];
			if (item != object)
				continue;
			item.dirty = true;
			member.rowHeads[r].dirty = true;
			member.colHeads[c].dirty = true;
			member.dirty = true;
			if (!layout_member(this)->dirty)
				BLayout::dirty();
			return true;
		}
	}
	return true;
}
Align BGridLayout::align(const BObject* object) const
{
	auto it = member.items.find(object);
	return it->align;
}
const BRect& BGridLayout::area(const BObject* object) const
{
	auto it = member.items.find(object);
	return it->rect;
}

BObject* BGridLayout::find(const BString& name) const
{
	for (int r = 0; r < member.items.row(); r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			const LayoutItem& item = member.items[r][c];
			if (item.widget && item.widget->name() == name)
				return item.widget;
			if (item.spacer && item.spacer->name() == name)
				return item.spacer;
			if (item.spring && item.spring->name() == name)
				return item.spring;
			if (item.layout)
			{
				if (item.layout->name() == name)
					return item.layout;
				BObject* object = item.layout->find(name);
				if (object)
					return object;
			}
		}
	}
	return 0;
}
BWidget* BGridLayout::findWidget(const BString& name) const
{
	for (int r = 0; r < member.items.row(); r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			const LayoutItem& item = member.items[r][c];
			if (item.widget && item.widget->name() == name)
				return item.widget;
			if (item.layout)
			{
				BWidget* widget = item.layout->findWidget(name);
				if (widget)
					return widget;
			}
		}
	}
	return 0;
}
BLayout* BGridLayout::findLayout(const BString& name) const
{
	for (int r = 0; r < member.items.row(); r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			const LayoutItem& item = member.items[r][c];
			if (item.layout)
			{
				if (item.layout->name() == name)
					return item.layout;
				BLayout* layout = item.layout->findLayout(name);
				if (layout)
					return layout;
			}
		}
	}
	return 0;
}
BSpacer* BGridLayout::findSpacer(const BString& name) const
{
	for (int r = 0; r < member.items.row(); r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			const LayoutItem& item = member.items[r][c];
			if (item.spacer && item.spacer->name() == name)
				return item.spacer;
			if (item.layout)
			{
				BSpacer* spacer = item.layout->findSpacer(name);
				if (spacer)
					return spacer;
			}
		}
	}
	return 0;
}
BSpring* BGridLayout::findSpring(const BString& name) const
{
	for (int r = 0; r < member.items.row(); r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			const LayoutItem& item = member.items[r][c];
			if (item.spring && item.spring->name() == name)
				return item.spring;
			if (item.layout)
			{
				BSpring* spring = item.layout->findSpring(name);
				if (spring)
					return spring;
			}
		}
	}
	return 0;
}

bool BGridLayout::contain(const BWidget* widget) const
{
	if (!widget)
		return false;
	for (int r = 0; r < member.items.row(); r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			const LayoutItem& item = member.items[r][c];
			if (item.widget == widget)
				return true;
			if (item.layout && item.layout->contain(widget))
				return true;
		}
	}
	return false;
}
bool BGridLayout::contain(const BLayout* layout) const
{
	if (!layout)
		return false;
	for (int r = 0; r < member.items.row(); r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			const LayoutItem& item = member.items[r][c];
			if (item.layout == layout)
				return true;
			if (item.layout && item.layout->contain(layout))
				return true;
		}
	}
	return false;
}
bool BGridLayout::contain(const BSpacer* spacer) const
{
	if (!spacer)
		return false;
	for (int r = 0; r < member.items.row(); r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			const LayoutItem& item = member.items[r][c];
			if (item.spacer == spacer)
				return true;
			if (item.layout && item.layout->contain(spacer))
				return true;
		}
	}
	return false;
}
bool BGridLayout::contain(const BSpring* spring) const
{
	if (!spring)
		return false;
	for (int r = 0; r < member.items.row(); r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			const LayoutItem& item = member.items[r][c];
			if (item.spring == spring)
				return true;
			if (item.layout && item.layout->contain(spring))
				return true;
		}
	}
	return false;
}

bool BGridLayout::remove(BWidget* widget)
{
	if (!widget)
		return false;
	if (widget_member(widget)->upperLayout == this)
		return false;
	auto it = member.items.find(widget);
	if (it.empty())
		return false;
	widget_member(widget)->upperLayout = 0;
	if (this->host())
		this->host()->removeChild(widget);
	it->widget = 0;
	member.dirtyCell(it.row(), it.column());
	BLayout::dirty();
	return true;
}
bool BGridLayout::remove(BLayout* layout)
{
	if (!layout)
		return false;
	if (layout_member(layout)->parent != this)
		return false;
	auto it = member.items.find(layout);
	if (it.empty())
		return false;
	if (this->host())
		layout->setHost(0);
	layout_member(layout)->parent = 0;
	it->layout = 0;
	member.dirtyCell(it.row(), it.column());
	BLayout::dirty();
	return true;
}
bool BGridLayout::remove(BSpacer* spacer)
{
	if (!spacer)
		return false;
	if (spacer_member(spacer)->layout != this)
		return false;
	auto it = member.items.find(spacer);
	if (it.empty())
		return false;
	spacer_member(spacer)->layout = 0;
	it->layout = 0;
	member.dirtyCell(it.row(), it.column());
	BLayout::dirty();
	return true;
}
bool BGridLayout::remove(BSpring* spring)
{
	if (!spring)
		return false;
	if (spring_member(spring)->layout != this)
		return false;
	auto it = member.items.find(spring);
	if (it.empty())
		return false;
	spring_member(spring)->layout = 0;
	it->layout = 0;
	member.dirtyCell(it.row(), it.column());
	BLayout::dirty();
	return true;
}
void BGridLayout::clear()
{
	if (member.items.size())
	{
		if (BWidget* host = this->host())
		{
			for (LayoutItem& item : member.items)
			{
				if (item.widget)
					host->removeChild(item.widget);
				if (item.layout)
					item.layout->setHost(0);
			}
		}
		member.items.clear();
		member.colHeads.clear();
		member.rowHeads.clear();
		BLayout::dirty();
	}
}

BSizePolicy BGridLayout::sizePolicy() const
{
	BSizePolicy policy = layout_member(this)->sizePolicy;
	if (policy.widthPolicy() == Policy_None || policy.heightPolicy() == Policy_None)
	{
		member.prepareCells();
		if (policy.widthPolicy() == Policy_None)
		{
			for (int i = 0; i < member.colHeads.size(); i++)
				policy.widthPolicy() |= member.colHeads[i].sizePolicy;
		}
		if (policy.heightPolicy() == Policy_None)
		{
			for (int i = 0; i < member.rowHeads.size(); i++)
				policy.heightPolicy() |= member.rowHeads[i].sizePolicy;
		}
	}
	return policy;

}
BSize BGridLayout::sizeHint() const
{
	member.prepareCells();
	const BMargin& margin = this->margin();
	int spacing = member.spacing;

	int hintWidth = 0;
	for (int i = 0; i < member.colHeads.size(); i++)
	{
		Policy policy = member.colHeads[i].sizePolicy;
		hintWidth += member.colHeads[i].hintSize;
		hintWidth += spacing;
	}
	hintWidth -= spacing;
	if (hintWidth < 0)
		hintWidth = 0;

	int hintHeight = 0;
	for (int i = 0; i < member.rowHeads.size(); i++)
	{
		Policy policy = member.rowHeads[i].sizePolicy;
		hintHeight += member.rowHeads[i].hintSize;
		hintHeight += spacing;
	}
	hintHeight -= spacing;
	if (hintHeight < 0)
		hintHeight = 0;

	return BSize(hintWidth + margin.left() + margin.right(), hintHeight + margin.top() + margin.bottom());
}
BSize BGridLayout::minSize() const
{
	member.prepareCells();
	const BMargin& margin = this->margin();
	int spacing = member.spacing;
	int minWidth = margin.left() + margin.right();
	int minHeight = margin.top() + margin.bottom();
	for (int i = 0; i < member.colHeads.size(); i++)
		minWidth += spacing + member.colHeads[i].minSize;
	for (int i = 0; i < member.rowHeads.size(); i++)
		minHeight += spacing + member.rowHeads[i].minSize;
	BSize minSize(minWidth - spacing, minHeight - spacing);
	minSize.limit(layout_member(this)->minSize, layout_member(this)->maxSize);
	return minSize;
}
BSize BGridLayout::maxSize() const
{
	member.prepareCells();
	const BMargin& margin = this->margin();
	int spacing = member.spacing;
	int maxWidth = margin.left() + margin.right();
	int maxHeight = margin.top() + margin.bottom();
	for (int i = 0; i < member.colHeads.size(); i++)
		maxWidth += spacing + member.colHeads[i].maxSize;
	for (int i = 0; i < member.rowHeads.size(); i++)
		maxHeight += spacing + member.rowHeads[i].maxSize;
	BSize maxSize(maxWidth - spacing, maxHeight - spacing);
	maxSize.limit(layout_member(this)->minSize, layout_member(this)->maxSize);
	return maxSize;
}
BSize BGridLayout::size() const
{
	BSize size;
	if (member.items.size())
	{
		for (int i = 0; i < member.colHeads.size(); i++)
			size.width() += member.colHeads[i].realSize;
		for (int r = 0; r < member.rowHeads.size(); r++)
			size.height() += member.rowHeads[r].realSize;
	}
	return size;
}
bool BGridLayout::adjust() const
{
	if (!layout_member(this)->dirty)
		return false;

	if (this->rect().empty())
	{
		for (auto it = member.items.begin(); it != member.items.end(); it++)
		{
			it->adjust(0, 0, 0, 0);
		}
		layout_member(this)->dirty = false;
		return false;
	}

	member.prepareCells();
	member.distributeWidth();
	member.distributeHeight();
	member.applyRects();

	layout_member(this)->dirty = false;
	return true;
}

bool BGridLayout::event(const BEvent& event)
{
	for (auto it = member.items.begin(); it.valid(); ++it)
	{
		BLayout* layout = it->layout;
		if (layout && layout->enabled())
		{
			if (layout_member(layout)->event(event))
				return true;
		}
	}
	return BLayout::event(event);
}

void BGridLayout::styleEvent(const BEvent& event)
{
	const BStyle* style = event.value();

	bool changed = false;
	const BValue& spaceValue = style->value(Value_Space);
	if (spaceValue.valid())
	{
		member.spacing = spaceValue;
		changed = true;
	}

	const BValue& handleSizeValue = style->value(Value_Handle_Size);
	if (handleSizeValue.valid())
	{
		member.handleSize = handleSizeValue;
		changed = true;
	}

	BLayout::dirty();
}
void BGridLayout::freshEvent(const BEvent& event)
{

}
void BGridLayout::paintEvent(const BEvent& event)
{
	BPainter painter(this->host());
	if (member.handleSize.height() > 0)
	{
		for (int i = 0; i < member.rowHeads.size() - 1; i++)
		{
			BRectf rect = member.rowHandleRect(i);
			rect.top() = rect.center().y() - member.handleSize.height() * 0.5f;
			rect.bottom() = rect.top() + member.handleSize.height();
			StyleRole colroRole = Color_Handle;
			if (i == member.rowHandle)
			{
				if (member.pressed)
					colroRole = Color_Handle_Pressed;
				else
					colroRole = Color_Handle_Hovered;
			}
			if (painter.setColor(colroRole))
				painter.fillRect(rect);
		}
	}
	if (member.handleSize.width() > 0)
	{
		for (int i = 0; i < member.colHeads.size() - 1; i++)
		{
			BRectf rect = member.columnHandleRect(i);
			rect.left() = rect.center().x() - member.handleSize.width() * 0.5f;
			rect.right() = rect.left() + member.handleSize.width();
			StyleRole colroRole = Color_Handle;
			if (i == member.columnHandle)
			{
				if (member.pressed)
					colroRole = Color_Handle_Pressed;
				else
					colroRole = Color_Handle_Hovered;
			}
			if (painter.setColor(colroRole))
				painter.fillRect(rect);
		}
	}
}

bool BGridLayout::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	member.rowHandle = -1;
	member.columnHandle = -1;
	return false;
}
bool BGridLayout::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	if (member.rowHandle >= 0)
	{
		member.rowHandle = -1;
		this->host()->setCursor(Cursor_None);
		this->fresh();
	}
	if (member.columnHandle >= 0)
	{
		member.columnHandle = -1;
		this->host()->setCursor(Cursor_None);
		this->fresh();
	}
	return false;
}

bool BGridLayout::mousePressEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		if (member.rowHandle >= 0 || member.columnHandle >= 0)
		{
			member.pressed = true;
			if (member.rowHandle >= 0)
			{
				member.pressCenter.y() = member.rowHandleRect(member.rowHandle).y();
				for (int i = 0; i < member.items.row(); i++)
				{
					member.rowHeads[i].metaSize = member.rowHeads[i].realSize;
					member.rowHeads[i].dragSize = member.rowHeads[i].realSize;
				}
			}
			if (member.columnHandle >= 0)
			{
				member.pressCenter.x() = member.columnHandleRect(member.columnHandle).x();
				for (int i = 0; i < member.items.column(); i++)
				{
					member.colHeads[i].metaSize = member.colHeads[i].realSize;
					member.colHeads[i].dragSize = member.colHeads[i].realSize;
				}
			}
			this->fresh();
			return true;
		}
	}
	return false;
}
bool BGridLayout::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		if (member.pressed != false)
		{
			member.pressed = false;
			this->fresh();
			return true;
		}
	}
	return false;
}
bool BGridLayout::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	if (member.pressed)
	{
		if (member.dragHandle(mouseEvent.pos()))
		{
			BWidget* host = this->host();
			widget_member(host)->procEvent(Event_Adjust);
		}
		this->fresh();
		return true;
	}
	else
	{
		const BPoint& pos = mouseEvent.pos();
		int rowHandle = -1;
		for (int i = 0; i < member.rowHeads.size() - 1; i++)
		{
			BRect handleRect = member.rowHandleRect(i);
			if (handleRect.contain(pos))
			{
				rowHandle = i;
				break;
			}
		}
		int columnHandle = -1;
		for (int i = 0; i < member.colHeads.size() - 1; i++)
		{
			BRect handleRect = member.columnHandleRect(i);
			if (handleRect.contain(pos))
			{
				columnHandle = i;
				break;
			}
		}
		member.checkRowHandle(rowHandle);
		member.checkColumnHandle(columnHandle);
		if (member.rowHandle != rowHandle || member.columnHandle != columnHandle)
		{
			member.rowHandle = rowHandle;
			member.columnHandle = columnHandle;
			if (member.rowHandle >= 0 && member.columnHandle >= 0)
				this->host()->setCursor(Cursor_SizeAll);
			else if (member.rowHandle >= 0)
				this->host()->setCursor(Cursor_SizeVer);
			else if (member.columnHandle >= 0)
				this->host()->setCursor(Cursor_SizeHor);
			else
				this->host()->setCursor(Cursor_None);
			this->fresh();
		}
		if (member.rowHandle >= 0 || member.columnHandle >= 0)
		{
			return true;
		}
	}
	return false;
}
